import random
import time
from datetime import datetime
from dao.exam_records_dao import ExamRecordDAO
from dao.exam_question_details_dao import ExamQuestionDetailDAO
from dao.questions_dao import QuestionDAO
from dao.error_questions_dao import ErrorQuestionDAO
from models.exam_record import ExamRecord
from models.exam_question_detail import ExamQuestionDetail
from models.error_question import ErrorQuestion
from configs import EXAM_CONFIG
from utils import log_error, log_exception, log_info, log_debug

class ExamService:
    def __init__(self):
        self.exam_records_dao = ExamRecordDAO()
        self.exam_question_details_dao = ExamQuestionDetailDAO()
        self.questions_dao = QuestionDAO()
        self.error_questions_dao = ErrorQuestionDAO()
        
        # 考试配置
        self.exam_config = EXAM_CONFIG

    def create_exam(self, user_id, category):
        """
        创建一场新考试
        :param user_id: 用户ID
        :param category: 考试类别
        :return: 考试记录ID和题目列表
        """
        # 获取配置
        config = self.exam_config.get(category, self.exam_config['A'])

        # 直接从数据库随机获取题目
        selected_single = self.questions_dao.get_random_questions_by_category_and_type(category, 1, config['single'])
        selected_multiple = self.questions_dao.get_random_questions_by_category_and_type(category, 2, config['multiple'])

        # 计算实际可用的题目数量
        actual_single = len(selected_single)
        actual_multiple = len(selected_multiple)

        # 检查是否有足够的题目
        if actual_single + actual_multiple == 0:
            return None, []

        # 更新配置
        config['single'] = actual_single
        config['multiple'] = actual_multiple
        config['total'] = actual_single + actual_multiple

        # 合并题目并打乱顺序
        exam_questions = selected_single + selected_multiple
        random.shuffle(exam_questions)

        # 打乱每个题目的选项顺序并更新正确答案
        shuffled_questions = self._shuffle_options(exam_questions)

        # 创建考试记录
        exam_record = ExamRecord(
            category=category,
            exam_date=datetime.now().strftime('%Y-%m-%d %H:%M:%S'),
            user_id=user_id
        )
        exam_id = self.exam_records_dao.create(exam_record)

        # 检查考试记录是否创建成功
        if exam_id is None:
            log_error("创建考试记录失败")
            return None, [], config

        # 保存考试题目详情
        self._save_exam_question_details(exam_id, shuffled_questions)

        return exam_id, shuffled_questions, config

    def get_exam_record_by_id(self, exam_id):
        """
        根据考试ID获取考试记录
        :param exam_id: 考试ID
        :return: 考试记录对象
        """
        return self.exam_records_dao.get_by_id(exam_id)
    
    def get_exam_question_details(self, exam_id):
        """
        根据考试ID获取考试题目详情
        :param exam_id: 考试ID
        :return: 考试题目详情列表
        """
        return self.exam_question_details_dao.get_by_exam_id(exam_id)
    
    def _shuffle_options(self, questions):
        """
        打乱题目选项并更新正确答案
        :param questions: 题目列表
        :return: 打乱选项后的题目列表
        """
        for question in questions:
            # 保存原始选项和正确答案
            original_options = {'A': question.A, 'B': question.B, 'C': question.C, 'D': question.D}
            correct_answer = question.T

            # 创建选项列表(保留键值对)并打乱
            options = list(original_options.items())
            random.shuffle(options)

            # 重新赋值打乱后的选项
            question.A, question.B, question.C, question.D = [opt[1] for opt in options[:4]]

            # 创建原始选项到新选项的映射
            original_to_new = {opt[0]: chr(65 + i) for i, opt in enumerate(options)}

            # 更新正确答案
            new_correct = ''
            for char in correct_answer:
                # 过滤掉非字母字符(如空格)
                if char.isalpha():
                    new_correct += original_to_new[char]

            # 对新的正确答案进行排序（多选题）
            if len(new_correct) > 1:
                new_correct = ''.join(sorted(new_correct))

            question.T = new_correct

        return questions

    def _save_exam_question_details(self, exam_id, questions):
        """
        保存考试题目详情
        :param exam_id: 考试ID
        :param questions: 题目列表
        """
        if not questions:
            return

        # 创建考试题目详情列表
        exam_question_details = []
        for question in questions:
            exam_question_detail = ExamQuestionDetail(
                exam_id=exam_id,
                question_id=question.id,
                question_text=question.Q,
                option_a=question.A,
                option_b=question.B,
                option_c=question.C,
                option_d=question.D,
                correct_answer=question.T,
                type=question.type,
                image_data=question.F
            )
            exam_question_details.append(exam_question_detail)

        # 使用批量插入
        self.exam_question_details_dao.bulk_create(exam_question_details)

    def submit_exam(self, exam_id, user_answers, start_time):
        """
        提交考试
        :param exam_id: 考试ID
        :param user_answers: 用户答案字典
        :param start_time: 开始时间
        :return: 考试结果
        """
        # 计算考试时长
        duration_seconds = time.time() - start_time

        # 更新考试记录
        exam_record = self.exam_records_dao.get_by_id(exam_id)
        if exam_record:
            exam_record.duration_seconds = duration_seconds
            self.exam_records_dao.update(exam_record)

        # 更新题目详情中的用户答案和正确性
        correct_count = 0
        total_count = 0
        user_id = exam_record.user_id
        category = exam_record.category

        exam_question_details = self.exam_question_details_dao.get_by_exam_id(exam_id)
        for detail in exam_question_details:
            question_id = detail.question_id
            total_count += 1

            log_debug(f"处理题目{question_id}, {user_answers}")
            
            if question_id in user_answers:
                user_answer, is_correct = user_answers[question_id]
                detail.user_answer = user_answer
                detail.is_correct = is_correct
                self.exam_question_details_dao.update(detail)

                if is_correct:
                    correct_count += 1
                else:
                    # 回答错误，添加到错题本
                    log_debug(f"考试{exam_id}中题目{question_id}回答错误，标记为错误")

                    # 检查题目是否已存在于错题本
                    log_debug(f"开始检查题目是否存在于错题本: 用户{user_id}, 题目{question_id}, 类别{category}")
                    existing_error = self.error_questions_dao.get_by_user_question_and_category(user_id, question_id, category)
                    log_debug(f"检查结果: 题目{question_id}存在于错题本: {existing_error is not None}")
                    
                    if not existing_error:
                        # 添加到错题本
                        log_debug(f"开始添加题目{question_id}到错题本")
                        error_question = ErrorQuestion(
                            question_id=question_id,
                            category=category,
                            user_id=user_id
                        )
                        log_debug(f"创建错题对象: {error_question.__dict__()}")
                        result = self.error_questions_dao.create(error_question)
                        if result:
                            log_debug(f"将考试{exam_id}中回答错误的题目{question_id}添加到错题本成功，生成的ID: {result}")
                        else:
                            log_debug(f"将考试{exam_id}中回答错误的题目{question_id}添加到错题本失败")
                    else:
                        log_debug(f"考试{exam_id}中回答错误的题目{question_id}已存在于错题本，ID: {existing_error.error_id}")
            else:
                # 未作答，添加到错题本
                detail.user_answer = ''
                detail.is_correct = False
                self.exam_question_details_dao.update(detail)
                log_debug(f"考试{exam_id}中题目{question_id}未作答，标记为错误")

                # 检查题目是否已存在于错题本
                log_debug(f"开始检查题目是否存在于错题本: 用户{user_id}, 题目{question_id}, 类别{category}")
                existing_error = self.error_questions_dao.get_by_user_question_and_category(user_id, question_id, category)
                log_debug(f"检查结果: 题目{question_id}存在于错题本: {existing_error is not None}")
                
                if not existing_error:
                    # 添加到错题本
                    log_debug(f"开始添加题目{question_id}到错题本")
                    error_question = ErrorQuestion(
                        question_id=question_id,
                        category=category,
                        user_id=user_id
                    )
                    log_debug(f"创建错题对象: {error_question.__dict__()}")
                    result = self.error_questions_dao.create(error_question)
                    if result:
                        log_debug(f"将考试{exam_id}中未作答的题目{question_id}添加到错题本成功，生成的ID: {result}")
                    else:
                        log_debug(f"将考试{exam_id}中未作答的题目{question_id}添加到错题本失败")
                else:
                    log_debug(f"考试{exam_id}中未作答的题目{question_id}已存在于错题本，ID: {existing_error.error_id}")

        # 返回考试结果
        return {
            'exam_id': exam_id,
            'correct_count': correct_count,
            'total_count': total_count,
            'duration_seconds': duration_seconds
        }

    def invalidate_exam(self, exam_id):
        """
        作废考试记录（删除考试记录和相关题目详情）
        :param exam_id: 考试ID
        :return: 是否作废成功
        """
        try:
            # 先删除考试题目详情
            detail_delete_success = self.exam_question_details_dao.delete_by_exam_id(exam_id)
            if not detail_delete_success:
                log_error(f"删除考试{exam_id}的题目详情失败")
                return False

            # 再删除考试记录
            record_delete_success = self.exam_records_dao.delete(exam_id)
            if not record_delete_success:
                log_error(f"删除考试记录{exam_id}失败")
                return False

            log_debug(f"作废考试{exam_id}成功")
            return True
        except Exception as e:
            log_exception(f"作废考试{exam_id}失败: {str(e)}")
            return False

    def get_exam_result(self, exam_id):
        """
        获取考试结果
        :param exam_id: 考试ID
        :return: 考试结果
        """
        exam_record = self.exam_records_dao.get_by_id(exam_id)
        if not exam_record:
            return None

        exam_question_details = self.exam_question_details_dao.get_by_exam_id(exam_id)
        correct_count = sum(1 for detail in exam_question_details if detail.is_correct)
        total_count = len(exam_question_details)

        # 获取配置
        config = self.exam_config.get(exam_record.category, self.exam_config['A'])
        pass_exam = correct_count >= config['pass_score']

        return {
            'exam_id': exam_id,
            'category': exam_record.category,
            'exam_date': exam_record.exam_date,
            'duration_seconds': exam_record.duration_seconds,
            'correct_count': correct_count,
            'total_count': total_count,
            'pass_exam': pass_exam,
            'pass_score': config['pass_score']
        }

    def get_exam_questions(self, exam_id):
        """
        获取考试题目
        :param exam_id: 考试ID
        :return: 题目列表
        """
        return self.exam_question_details_dao.get_by_exam_id(exam_id)

    def get_user_exam_records(self, user_id, category=None, limit=5):
        """
        获取用户考试记录
        :param user_id: 用户ID
        :param category: 考试类别(可选)
        :param limit: 限制数量
        :return: 考试记录列表
        """
        if category:
            return self.exam_records_dao.get_by_user_and_category(user_id, category)
        else:
            return self.exam_records_dao.get_recent_exams(user_id, limit)

    def get_exam_config(self, category):
        """
        获取考试配置
        :param category: 考试类别
        :return: 考试配置
        """
        return self.exam_config.get(category, self.exam_config['A'])